import time
import json
import check_passwd
import random
from decimal import Decimal
import pandas as pd
from pandas import DataFrame
import re

"""
还有不足，慢慢修改,会有些许逻辑问题，没时间检测了！
"""

# 全局变量初始化
# name -->登录后记录用户名全局使用
# money -->用户余额
# com_count -->商品编号
# com_num -->商品数量
# com_name -->商品名称
# fre -->用于日志记录用户第几次的购买
name = com_count = com_num = com_name = money = fre = ""

# 初始化日志标记
log_num = 0

# 用于格式化输出表格
tplt = "{0:{4}^10}\t{1:{4}^10}\t{2:{4}^10}\t{3:{4}^10}"
tplt1 = "{0:{4}^10}\t{1:{4}^15}\t{2:{4}^12}\t{3:{4}^13}"
tplt2 = "{0:{3}^10}\t{1:{3}^15}\t{2:{3}^12}"


# 读取信息
# flag = 1 -->读取用户信息
# flag = 2 -->读取商品信息
# flag = 3 -->修读取用户购物车信息
def read(flag):
    if flag == 1:
        with open("shuserinfo.txt", "r") as f:
            return json.load(f)
    elif flag == 2:
        with open("commodity.txt", "r") as f:
            return json.load(f)
    elif flag == 3:
        with open(f"{name}.txt", "r") as f:
            return json.load(f)


# 修改用户列表
# flag = 1 -->修改用户信息
# flag = 2 -->修改商品信息
# flag = 3 -->增加购物车信息
# flag = 4 -->清空购物车信息
def wirt(flag, dicts):
    if flag == 1:
        with open("shuserinfo.txt", "w", encoding="utf-8") as f:
            json.dump(dicts, f, indent=4, sort_keys=True)
    elif flag == 2:
        with open("commodity.txt", "w", encoding="utf-8") as f:
            json.dump(dicts, f, indent=4, sort_keys=True)
    elif flag == 3:
        with open(f"{name}.txt", "w", encoding="utf-8") as f:
            json.dump(dicts, f, indent=4, sort_keys=True)
    elif flag == 4:
        with open(f"{name}.txt", "w", encoding="utf-8") as f:
            json.dump("购物车空空如也！快去购物吧！", f)


# 用户登录
def login():
    # 全局用户名方便调用，余额方便调用及修改
    global name, money
    # 获取用户的账号密码余额的字典
    user_dict = read(1)
    print("ps.输入quit即可退出".center(50))
    while True:
        # 用于三次后禁止五秒输入
        for i in range(3):
            name = input("输入用户名:")
            if name in user_dict.keys():
                passwd = input("请输入密码：")
                if passwd == "":
                    print("密码不能为空！".center(50))
                elif passwd == "quit":
                    print("即将退出...".center(50))
                    time.sleep(3)
                    print("欢迎下次使用！".center(50))
                    print("-".rjust(50, '-'))
                    return
                elif passwd == user_dict.get(name)[0]:
                    # 记录余额全局使用，方便后面修改
                    money = user_dict.get(name)[1]
                    print("登录成功！".center(50))
                    print(f"欢迎\033[36;1m{name}\033[0m!余额为：\033[36;1m{money}\033[0m元".center(70))
                    print("-".rjust(50, '-'))
                    menu_se()
                    return
                else:
                    print("密码错误！".center(50))
            elif name == "":
                print("用户名不能为空！".center(50))
            elif name == "quit":
                print("即将退出...".center(50))
                time.sleep(1)
                print("欢迎下次使用！".center(50))
                print("-".rjust(50, '-'))
                return
            else:
                print("用户名错误！".center(50))
        print("\033[41;33m已错误三次！请五秒后再尝试！\033[0m".center(50))
        time.sleep(5)


# 用户注册
def logon():
    global name
    # 获取用户信息
    user_dict = read(1)
    while 1:
        name = input("请输入新用户的名字：")
        # 用过字典查找防止用户名重复
        if name in user_dict.keys():
            print("该用户名已被使用！".center(50))
        elif name == "":
            print("用户名不能为空！".center(50))
        else:
            break
    print("注意：密码需符合密码复杂度要求！(即分数为5分)".center(50))
    print("1.必须超过八位".center(50))
    print("2.必须由数字，大写字母，小写，特殊符号三种以上组成".center(50))
    print("3.不可重复三个以上的字符".center(50))
    while 1:
        new_passwd = input("请输入新用户的密码：")
        # 通过调用check_passwd()函数对密码判断
        tem_list = check_passwd.check_passwd(passwd=new_passwd)
        if new_passwd == "":
            print("密码不能为空！".center(50))
        elif "▪长度小于8 " in tem_list[1]:
            print(f"密码级别为：{tem_list[0]}\n"
                  "密码必须超过八位！")
        elif tem_list[0] < 5:
            print(f"密码级别为：{tem_list[0]}\n{tem_list[1]}")
        else:
            break
    # 增加用户信息字典，方便录入（修改
    user_dict[name] = [new_passwd, '0']
    # 修改用户信息表
    wirt(1, user_dict)
    # 新建用户个人购物车
    wirt(4, user_dict)
    print(f"新用户{name}添加完毕！".center(50))
    print(f"新用户{name}信息如下：".center(50))
    print("*".rjust(50, '*'))
    # 刷新一下从库中验证更新用户信息成功，并显示
    user_dict = read(1)
    print(tplt2.format("用户", "密码", "余额", " "))
    print(tplt2.format(name, user_dict.get(name)[0], user_dict.get(name)[1], " "))
    print("*".rjust(50, '*'))
    input("按回车返回主菜单".center(50))
    # 新建用户后返回以及菜单
    menu_fr()
    return


# 商品展示及购买
def com_list():
    # 获取商品信息的字典
    com_dict = read(2)
    print("*".rjust(70, '*'))
    print(tplt1.format("商品编号", "商品", "价格", "剩余数量", " "))
    # 通过循环输出商品列表
    for i, j in com_dict.items():
        print(tplt.format(i, j[0], j[1], j[2], chr(12288)))
    print("*".rjust(70, '*'))
    print("1.加入购物车".center(50))
    print("2.直接购买".center(50))
    print("3.返回菜单".center(50))
    print("4.退出".center(50))
    print("-".rjust(50, "-"))
    while 1:
        choice = input("请选择：")
        if choice == "1":
            car_buy(1)
            return
        elif choice == "2":
            car_buy(2)
            return
        elif choice == "3":
            print("#".rjust(50, "#"))
            # 通过调用返回上一级菜单
            menu_se()
            return
        elif choice == "4":
            log_rd(log_num)
            print("-".rjust(50, '-'))
            print("正在退出...".center(50))
            time.sleep(1)
            print("欢迎下次使用！".center(50))
            return
        else:
            print("请输入正确选项")
            print("-".rjust(50, "-"))


# 加入购物车/直接购买
def car_buy(flag):
    # 全局商品信息，方便后续调用
    global com_count, com_num, com_name
    # 读取商品列表
    com_dict = read(2)
    # 初始化
    where = ""
    # 通过flag判断从不同页面过来，做不同效果
    if flag == 1:
        where = "加入购物车"
    elif flag == 2:
        where = "购买"
    while 1:
        com_num = input(f"请输入要{where}的商品编号：")
        # 通过字典包含判断商品存在
        if com_num in com_dict.keys():
            com_name = com_dict.get(com_num)[0]
            com_count = input(f"请输入要{where}的商品数量：")
            if com_count == "":
                print("数量不能为空！".center(50))
            elif com_count == "quit":
                print("即将退出...".center(50))
                time.sleep(1)
                print("欢迎下次使用！".center(50))
                print("-".rjust(50, '-'))
                return
            elif int(com_count) > int(com_dict.get(com_num)[2]):
                print("库存数量不足！请等待进货...")
                print("正在返回商品浏览界面...")
                time.sleep(1)
                com_list()
                return
            elif int(com_count) <= int(com_dict.get(com_num)[2]):
                tem = com_dict[com_num]
                if flag == 1:
                    car_dict = read(3)
                    if "购物车空空如也！快去购物吧！" in car_dict:
                        car_dict = {}
                    car_dict[com_num] = [tem[0], tem[1], int(com_count)]
                    wirt(3, car_dict)
                    print(f"已成功{where}！")
                    input("按回车继续购物")
                    com_list()
                elif flag == 2:
                    cost = Decimal(tem[1]) * Decimal(com_count)
                    pay(1, cost)
                return
            else:
                print("请输入正确数值！")
        elif com_num == "":
            print("商品编号不能为空！".center(50))
        elif com_num == "quit":
            print("即将退出...".center(50))
            time.sleep(1)
            print("欢迎下次使用！".center(50))
            print("-".rjust(50, '-'))
            return
        else:
            print("请输入正确的商品编号！")


# 购物车
def shop_car():
    # 获取用户购物车
    car_dict = read(3)
    # 初始化
    cost = Decimal(0)
    if car_dict == "购物车空空如也！快去购物吧！":
        print(car_dict)
        input("按回车去浏览商品")
        com_list()
        return
    else:
        print("*".rjust(70, '*'))
        print(tplt1.format("商品编号", "商品", "单价", "购买数量", " "))
        for i, j in car_dict.items():
            cost = Decimal(cost) + (Decimal(j[1]) * Decimal(j[2]))
            print(tplt.format(i, j[0], j[1], j[2], chr(12288)))
        print("*".rjust(70, '*'))
        print("1.确认购买".center(50))
        print("2.浏览商品".center(50))
        print("3.返回菜单".center(50))
        print("4.退出".center(50))
        print("-".rjust(50, "-"))
        while 1:
            choice = input("请选择：")
            if choice == "1":
                pay(2, cost)
                # 清空购物车
                wirt(4, "")
                return
            elif choice == "2":
                com_list()
                return
            elif choice == "3":
                print("#".rjust(50, "#"))
                menu_se()
                return
            elif choice == "4":
                log_rd(log_num)
                print("-".rjust(50, '-'))
                print("正在退出...".center(50))
                time.sleep(1)
                print("欢迎下次使用！".center(50))
                return
            else:
                print("请输入正确选项")
                print("-".rjust(50, "-"))


# 付钱
def pay(flag, all_cost):
    global money, log_num
    user_dict = read(1)
    com_dict = read(2)
    print("-".rjust(50, "-"))
    print(f"总共花费：{all_cost}，您的余额为：{money}")
    while 1:
        buy = input("是否确认购买(Y/N)：")
        if buy == "Y":
            if all_cost > Decimal(money):
                print("余额不足！请充值！".center(50))
                input("按回车转跳至充值界面".center(50))
                print("正在跳转至充值界面...")
                print("-".rjust(50, "-"))
                time.sleep(1)
                recharge(1)
            else:
                # 修改商品剩余数量
                com_dict[com_num][2] = int(com_dict[com_num][2]) - int(com_count)
                wirt(2, com_dict)
                print("购买成功！".center(50))
                # 修改用户余额（临时
                money = Decimal(money) - all_cost
                print(f"您的余额为：{money}".center(50))
                user_dict[name][1] = str(money)
                # 修改账户余额（写入
                wirt(1, user_dict)
                # 加入日志
                log_wt()
                # 更新日志标记
                log_num = 1
                input("按回车继续浏览商品")
                time.sleep(1)
                com_list()
                return
        elif buy == "N":
            # 通过flag判断返回上一个界面
            if flag == 1:
                com_list()
                return
            elif flag == 2:
                shop_car()
                return
        else:
            print("请输入正确选项！")
            print("-".rjust(50, "-"))


# 充值
def recharge(flag):
    global money
    user_dict = read(1)
    while 1:
        in_money = input("请输入需要充值的金额:")
        if in_money == "":
            print("充值金额不能为空！")
        elif in_money == "quit":
            print("-".rjust(50, '-'))
            print("正在退出...".center(50))
            time.sleep(1)
            print("欢迎下次使用！".center(50))
            return
        # 可以输入小数（但没有必要啊！ -->被 测试者被迫要求
        elif re.search(r'\d\.[0-9]+', in_money):
            # 原版判断数字，无法获取小数  in_money.isdigit():
            if Decimal(in_money) > 0:
                print("请扫描二维码支付！".center(50))
                # 输出二维码
                for i in range(10):
                    for j in range(20):
                        a = random.randint(0, 2)
                        if a == 0:
                            print("\033[40;36m  \033[0m", end="")
                        else:
                            print("  ", end="")
                    print("")
                print("\n\n")
                print("按回车继续".center(50))
                time.sleep(3)
                print("支付成功！".center(50))
                # 修改账户余额并写入
                money = Decimal(in_money) + Decimal(money)
                user_dict[name][1] = str(money)
                wirt(1, user_dict)
                print(f"您当前的余额为：\033[36;1m{money}\033[0m元")
                if flag == 1:
                    com_list()
                else:
                    menu_se()
                return
            else:
                print("请输入正确充值金额！")
        else:
            print("请输入正确充值金额！")


# 记录日志
def log_wt():
    global fre
    # 把本次消费保存进log日志文件(xlsx文件  此处运用pandas
    df = pd.read_excel('log.xlsx')
    # fre用于记录用户第几次购买的东西，用于退出后输出本次购买内容
    fre = 1
    # 通过循环判断用户第几次购买（数据多比较耗时间
    while 1:
        check = str(df.loc[df['购买用户'] == f"{name}{fre}", ['商品编号', '商品名称', '购买数量']])
        if "Empty DataFrame" in check:
            break
        else:
            fre += 1
    # 利用excel特性，会自动向前排序排去末尾，写入个极大值即可  -->暂时没发现问题
    df.loc[999] = [com_num, com_name, com_count, name + str(fre)]
    DataFrame(df).to_excel('log.xlsx', sheet_name='sheet1', index=False, header=True)


# 展示日志
def log_rd(flag):
    # 通过flag判断有无购买，节省查找日志时间
    if flag == 0:
        print("本次什么也没有购买！".center(50))
    else:
        print("本次的消费清单如下：".center(50))
        # pandas读取表格，自动以“表格”输出
        df = pd.read_excel('log.xlsx')
        print(df.loc[df['购买用户'] == f"{name}{fre}", ['商品编号', '商品名称', '购买数量']])


# 一级主菜单
def menu_fr():
    print("1.登录".center(50))
    print("2.注册".center(50))
    print("3.退出".center(50))
    print("-".rjust(50, "-"))
    while 1:
        choice = input("请选择:")
        if choice == "1":
            print("#".rjust(50, "#"))
            login()
            return
        elif choice == "2":
            print("#".rjust(50, "#"))
            logon()
            return
        elif choice == "3":
            log_rd(log_num)
            print("-".rjust(50, '-'))
            print("正在退出...".center(50))
            time.sleep(1)
            print("欢迎下次使用！".center(50))
            return
        else:
            print("请输入正确选项！")
            print("-".rjust(50, "-"))


# 二级菜单
def menu_se():
    print("1.浏览商品".center(50))
    print("2.购物车".center(50))
    print("3.充值".center(50))
    print("4.返回上一级菜单".center(50))
    print("5.退出".center(50))
    print("-".rjust(50, "-"))
    while 1:
        choice = input("请选择：")
        if choice == "1":
            com_list()
            return
        elif choice == "2":
            shop_car()
            return
        elif choice == "3":
            recharge(2)
            return
        elif choice == "4":
            print("正在返回...".center(50))
            time.sleep(1)
            print("-".rjust(50, '-'))
            menu_fr()
            return
        elif choice == "5":
            log_rd(log_num)
            print("-".rjust(50, '-'))
            print("正在退出...".center(50))
            time.sleep(1)
            print("欢迎下次使用！".center(50))
            return
        else:
            print("请输入正确选项！")
            print("-".rjust(50, "-"))

# 运行程序！！！
print("欢迎使用三乐购物系统！".center(50))
menu_fr()
